package model.searchers.linkedListSearcher;

import java.io.BufferedReader;
import java.io.IOException;

import model.searchers.GenericSearcher;


import model.searchers.linkedListSearcher.LinkedList;
import utilityClasses.Timer;
import model.searchers.URLList;

/**
 * Class LinkedListSearcher represents a the searcher functions needed to add and retrieve words from a linked list data structure. 
 * The class contains the constructor for the linked list searcher and method to read the input file and add the words to the data structure.
 */

public class LinkedListSearcher extends GenericSearcher {

	private LinkedList data = null; // reference to first element in linked list
	private LinkedList lastListElement = null; // reference to last element in linked list

	/**
	 * The constructor for linked list searcher. It needs parameters for the path to the file 
	 * and whether or whether not the searcher should support boolean search or not.
	 */
	
	public LinkedListSearcher(String fileName, boolean mode) throws IOException {
		Timer.printTime(loadData(fileName));
		super.setBooleanSearch(mode);
	}

	/**
	 * A method that reads the input file and adds the words to a linked list.
	 * @param fileName		Input file with the words needed to load
	 * @throws IOException	error catching
	 */
	private void readFile(String fileName) throws IOException {
		String line;
		// Open the file given as argument
		BufferedReader infile = this.getDataFromFile(fileName);
		line = infile.readLine(); // Read the next line
		while (line != null) { // Exit if there is none
			put(line);
			line = infile.readLine(); // Read the next line
		}
		infile.close(); // Close the file
	}
	
	/**
	 * Put a word into the linked list, if it is not null
	 * 
	 * @param value	word to be added to list
	 */
	@Override
	public void put(String value) {
		if (data != null) {
			LinkedList newElement = new LinkedList(value, null);
			lastListElement.setNext(newElement);
			lastListElement = newElement;
		} else {
			data = new LinkedList(value, null);
			lastListElement = data;
		}
		incrementTotalWordCount();
	}

	//to be used in more advanced searchers
	@Override
	public void put(String key, String value) {
		throw new UnsupportedOperationException(
				"Not supported, use put(String value)");
	}

	/**
	 * Get a linked list of the URLs on which a given search word occurs
	 * 
	 * @param key	search word
	 * @return linked list of URLs
	 */
	@Override
	public LinkedList get(String key) {
		LinkedList current = data;
		LinkedList result = null;
		String currentUrl = "No page set";
		String lastFoundUrl = null;
		while (current != null) {
			// if current string is an URL
			if (current.getValue().startsWith("*PAGE:")) {
				currentUrl = current.getValue().substring(6);
				// if the word is found
			} else if (current.getValue().equals(key)) {
				// if the key is found for the first time on the current page
				if (!currentUrl.equals(lastFoundUrl)) {
					LinkedList newResultElement = new LinkedList(currentUrl,
							result);
					result = newResultElement;
					lastFoundUrl = currentUrl;
				}
			}
			current = current.getNext();
		}
		if (isBooleanSearch()) {
			URLList resultTemp = null;
			while (result != null) {
				URLList temp = new URLList(result.getValue(), 0, resultTemp);
				resultTemp = temp;
				result = result.getNext();
			}
			result = resultTemp;
		}
		return result;
	}

	/**
	 * Reformat the result from a linked list to an array of Strings
	 * 
	 * @param structuredResult	 linked list to reformat
	 * @return A String array containing the words from the linked list
	 */
	@Override
	public String[] formatResult(LinkedList structuredResult) {
		if (structuredResult != null) {
			LinkedList temp = structuredResult;
			int size = 0;
			// count the number of results
			while (temp != null) {
				size++;
				temp = temp.getNext();
			}
			String[] result = new String[size];
			for (int i = 0; i < size; i++) {
				result[i] = structuredResult.getValue();
				structuredResult = structuredResult.getNext();
			}
			return result;
		} else {
			return null;
		}
	}
	
	/**
	 * Create a sample of specified size containing (pseudo)random search words from the nested linked list.
	 * To be used for benchmarking
	 * 
	 * @param sampleSize	size of sample
	 * @return	array of search words
	 */
	@Override
	public String[] createSample(int sampleSize) {
		//System.out.println("number of search words: " + getTotalWordCount());
		String[] sample = new String[sampleSize];
		int i = 0;
		while (i < sampleSize) {
			int index = (int) (Math.random() * getTotalWordCount());
			// System.out.println("index chosen: " + index);
			LinkedList temp = data.getFromList(index);
			if (temp != null && temp.getValue() != null) {
				if (!temp.getValue().contains("*PAGE")) {
					sample[i] = temp.getValue();
					i++;
				}
			}

		}

		return sample;
	}

	@Override
	public long loadData(String fileName) throws IOException {
		data = null;
		long time = Timer.startTime();
		readFile(fileName);
		long total_time = Timer.getTime(time);
		return total_time;
		
	}

	@Override
	public String toString() {
		String result = "Filename: " + this.getFileName() + "\r\nSearcher: " +this.getSearcherType() +  "\r\nBoolean Search: " + this.isBooleanSearch();
		return result;
		
	}

}
